package com.starsky.common.redis.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 */
@Component
public class RedisUtils {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 默认过期时长为24小时，单位：秒
     */
    public final static long DEFAULT_EXPIRE = 60 * 60 * 24L;
    /**
     * 不设置过期时长
     */
    public final static long NOT_EXPIRE = -1L;

    /**
     * 获取字符串操作
     *
     * @return
     */
    public ValueOperations getValueOperations() {
        ValueOperations<String, Object> options = redisTemplate.opsForValue();
        return options;
    }

    /**
     * key 存在时删除 key
     *
     * @param key
     */
    public Boolean delete(String key) {
        Boolean res = redisTemplate.delete(key);
        return res;
    }

    /**
     * 删除 key
     *
     * @param keys: 多个key
     */
    public Long delete(Collection<String> keys) {
        Long res = redisTemplate.delete(keys);
        return res;
    }

    /**
     * 删除 key
     *
     * @param pattern: key表达式
     */
    public Long deleteByPattern(String pattern) {
        Long res = redisTemplate.delete(keys(pattern));
        return res;
    }

    /**
     * 序列化给定 key ，并返回被序列化的值
     *
     * @param key
     */
    public byte[] dump(String key) {
        byte[] res = redisTemplate.dump(key);
        return res;
    }

    /**
     * 检查给定 key 是否存在
     *
     * @param key
     */
    public Boolean exists(String key) {
        Object res = get(key);
        if (res == null) {
            return false;
        }
        return true;
    }

    /**
     * 为key 设置过期时间
     * EXPIREAT 的作用和 EXPIRE 类似，都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
     *
     * @param key
     */
    public Boolean expireAt(String key, Date date) {
        Boolean res = redisTemplate.expireAt(key, date);
        return res;
    }

    /**
     * 为给定 key 设置过期时间，以秒计
     *
     * @param key：键
     * @param expire: 过期时间，单位秒
     */
    public Boolean expire(String key, long expire) {
        Boolean res = redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        return res;
    }

    /**
     * 为给定 key 设置过期时间，以秒计
     *
     * @param key：键
     * @param expire: 过期时间，单位,默认毫秒
     * @param unit:   单位,默认毫秒 TimeUnit.MILLISECONDS
     */
    public Boolean expire(String key, long expire, TimeUnit unit) {
        if (unit == null) unit = TimeUnit.MILLISECONDS;
        Boolean res = redisTemplate.expire(key, expire, unit);
        return res;
    }

    /**
     * 查询符合给定模式的 key 列表
     *
     * @param pattern：键
     */
    public Set<String> keys(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        return keys;
    }

    /**
     * 将当前数据库的数据 移动到给定的数据库 db 中
     *
     * @param desDbIndex：目标数据库
     */
    public void moveDB(int desDbIndex) {
        Set<String> keys = redisTemplate.keys("*");
        for (String key : keys) {
            Boolean res = redisTemplate.move(key, desDbIndex);
        }
    }

    /**
     * 将当前数据库的key 移动到给定的数据库 db 中
     *
     * @param key：键
     * @param dbIndex：数据库
     */
    public Boolean move(String key, int dbIndex) {
        Boolean res = redisTemplate.move(key, dbIndex);
        return res;
    }

    /**
     * 移除 key 的过期时间，key 将持久保持
     *
     * @param key：键
     */
    public Boolean persist(String key) {
        Boolean res = redisTemplate.persist(key);
        return res;
    }

    /**
     * 从当前数据库中随机返回一个 key
     */
    public String randomKey() {
        String key = redisTemplate.randomKey();
        return key;
    }

    /**
     * 重命名key
     *
     * @param oldKey: 旧键
     * @param newKey: 新键
     */
    public void rename(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * 原子操作修改key,仅当 newkey 不存在时，将 oldKey 改名为 newkey
     *
     * @param oldKey: 旧键
     * @param newKey: 新键
     * @return
     */
    public Boolean renameIfAbsent(String oldKey, String newKey) {
        Boolean res = redisTemplate.renameIfAbsent(oldKey, newKey);
        return res;
    }

    /**
     * 查询 key 所储存的值的类型
     *
     * @param key:键
     * @return
     */
    public DataType type(String key) {
        DataType type = redisTemplate.type(key);
        return type;
    }

    /**
     * 设置指定 key 的值
     *
     * @param key：键
     * @param value：值
     * @param expire：过期时间，单位秒
     */
    public void set(String key, Object value, long expire) {
        getValueOperations().set(key, value);
        if (expire != NOT_EXPIRE) {
            expire(key, expire);
        }
    }

//    public boolean set(final String key, final String value) {
//        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
//        boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
//            connection.set(serializer.serialize(key), serializer.serialize(value));
//            return true;
//        });
//        return result;
//    }
//
//    public String get(final String key) {
//        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
//        String result = redisTemplate.execute((RedisCallback<String>) connection -> {
//            byte[] value = connection.get(serializer.serialize(key));
//            return serializer.deserialize(value);
//        });
//        return result;
//    }

    /**
     * 设置指定 key 的值,默认缓存24小时
     *
     * @param key：键
     * @param value：值
     */
    public void set(String key, Object value) {
        set(key, value, DEFAULT_EXPIRE);
    }

    /**
     * 获取指定 key 的值
     *
     * @param key：键
     * @param expire：过期时间，单位秒
     */
    public Object get(String key, long expire) {
        Object value = getValueOperations().get(key);
        if (expire != NOT_EXPIRE) {
            expire(key, expire);
        }
        return value;
    }

    /**
     * 获取指定 key 的值
     *
     * @param key
     * @return
     */
    public Object get(String key) {
        Object value = getValueOperations().get(key);
        return value;
    }

    /**
     * 获取指定位置的 key 的值
     *
     * @param key
     * @return
     */
    public String get(String key, int start, int end) {
        String res = getValueOperations().get(key, start, end);
        return res;
    }

    /**
     * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
     *
     * @param key
     * @return
     */
    public Object getAndSet(String key, Object value) {
        Object res = getValueOperations().getAndSet(key, value);
        return res;
    }

    /**
     * 获取指定对 key 所储存的字符串值 的偏移量上的位(bit)。
     *
     * @param key：键
     * @param offset：偏移量
     * @return
     */
    public Boolean getBit(String key, int offset) {
        Boolean res = getValueOperations().getBit(key, offset);
        return res;
    }

    /**
     * 设置或清除指定key 所储存的字符串值 的偏移量上的位(bit)
     *
     * @param key：键
     * @param offset：偏移量
     * @return
     */
    public Boolean setBit(String key, int offset, boolean value) {
        Boolean res = getValueOperations().setBit(key, offset, value);
        return res;
    }

    /**
     * 获取所有(一个或多个)给定 key 的值
     *
     * @param keys
     * @return
     */
    public List<Object> mget(Collection<Object> keys) {
        List<Object> list = getValueOperations().multiGet(keys);
        return list;
    }

    /**
     * 设置一个或多个 key-value 对
     *
     * @param map: key-value键值对
     * @return
     */
    public void mSet(Map map) {
        getValueOperations().multiSet(map);
    }

    /**
     * 原子操作，设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在
     *
     * @param map: key-value键值对
     * @return
     */
    public Boolean multiSetIfAbsent(Map map) {
        Boolean res = getValueOperations().multiSetIfAbsent(map);
        return res;
    }

    /**
     * setNX操作，只有在 key 不存在时设置 key 的值
     *
     * @param key:   键
     * @param value： 值
     * @return
     */
    public Boolean setIfAbsent(String key, Object value) {
        Boolean res = getValueOperations().setIfAbsent(key, value);
        return res;
    }

    /**
     * setNX操作，只有在 key 不存在时设置 key 的值
     * 为指定的 key 设置值及其过期时间。如果 key 已经存在， SETEX 命令将会替换旧的值
     *
     * @param key:      键
     * @param value：    值
     * @param duration： 持续时间
     * @return
     */
    public Boolean setIfAbsent(String key, Object value, Duration duration) {
        Boolean res = getValueOperations().setIfAbsent(key, value, duration);
        return res;
    }

    /**
     * setNX操作，只有在 key 不存在时设置 key 的值
     * 为指定的 key 设置值及其过期时间。如果 key 已经存在， SETEX 命令将会替换旧的值
     *
     * @param key:      键
     * @param value：    值
     * @param duration： 持续时间
     * @param timeUnit： 时间单位
     * @return
     */
    public Boolean setIfAbsent(String key, Object value, long duration, TimeUnit timeUnit) {
        Boolean res = getValueOperations().setIfAbsent(key, value, duration, timeUnit);
        return res;
    }

    /**
     * 以毫秒为单位设置 key 的生存时间
     *
     * @param key:   键
     * @param value： 值
     * @return
     */
    public Boolean setIfPresent(String key, Object value) {
        Boolean res = getValueOperations().setIfPresent(key, value);
        return res;
    }

    /**
     * 以毫秒为单位设置 key 的生存时间
     *
     * @param key:      键
     * @param value：    值
     * @param duration： 持续时间
     * @return
     */
    public Boolean setIfPresent(String key, Object value, Duration duration) {
        Boolean res = getValueOperations().setIfPresent(key, value, duration);
        return res;
    }

    /**
     * 以毫秒为单位设置 key 的生存时间
     *
     * @param key:      键
     * @param value：    值
     * @param duration： 持续时间
     * @param timeUnit： 时间单位
     * @return
     */
    public Boolean setIfPresent(String key, Object value, long duration, TimeUnit timeUnit) {
        Boolean res = getValueOperations().setIfPresent(key, value, duration, timeUnit);
        return res;
    }

    /**
     * 将 key 中储存的数字加上指定的增量值
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCRBY 命令。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误
     *
     * @param key:   key
     * @param delta: 增量值
     * @return
     */
    public Long increment(String key, long delta) {
        Long increment = getValueOperations().increment(key, delta);
        return increment;
    }

    /**
     * 将 key 中储存的数字加上指定的增量值
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCRBY 命令。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误
     *
     * @param key:   key
     * @param delta: 增量值
     * @return
     */
    public Double increment(String key, double delta) {
        Double increment = getValueOperations().increment(key, delta);
        return increment;
    }

    /**
     * 将 key 中储存的数字值减一
     *
     * @param key
     * @return
     */
    public Long decrement(String key) {
        Long decrement = getValueOperations().decrement(key);
        return decrement;
    }

    /**
     * key 所储存的值减去给定的减量值（decrement）
     *
     * @param key
     * @param delta
     * @return
     */
    public Long decrement(String key, long delta) {
        Long decrement = getValueOperations().decrement(key, delta);
        return decrement;
    }

    /**
     * 如果 key 已经存在并且是一个字符串， APPEND 命令将指定的 value 追加到该 key 原来值（value）的末尾
     *
     * @param key
     * @param value
     * @return
     */
    public Integer append(String key, String value) {
        Integer res = getValueOperations().append(key, value);
        return res;
    }

    /**
     * 获取key指定字符串大小
     *
     * @param key
     * @return
     */
    public Long size(String key) {
        Long size = getValueOperations().size(key);
        return size;
    }
    /***************String operation method end*********************/


    /*****************HashMap operation method start **************/

    /**
     * 获取HashMap操作
     *
     * @return
     */
    public HashOperations getHashOperations() {
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        return hashOperations;
    }

    /**
     * 添加数据，将哈希表 key 中的字段 field 的值设为 value
     *
     * @param key:键
     * @param field：字段
     * @param value：值
     */
    public void put(String key, Object field, Object value) {
        put(key, field, value, DEFAULT_EXPIRE);
    }

    /**
     * 将哈希表 key 中的字段 field 的值设为 value
     *
     * @param key:键
     * @param field：字段
     * @param value：值
     * @param expire：过期时间，默认秒
     */
    public void put(String key, Object field, Object value, long expire) {
        getHashOperations().put(key, field, value);
        if (expire != NOT_EXPIRE) {
            expire(key, expire);
        }
    }

    /**
     * 将多个 field-value (域-值)对设置到哈希表 key 中，默认缓存24小时
     *
     * @param key:键
     * @param map：字段-值
     */
    public void putAll(String key, Map<String, Object> map) {
        putAll(key, map, DEFAULT_EXPIRE);
    }

    /**
     * 将多个 field-value (域-值)对设置到哈希表 key 中，默认缓存单位秒
     *
     * @param key:键
     * @param map：字段-值
     */
    public void putAll(String key, Map<String, Object> map, long expire) {
        getHashOperations().putAll(key, map);
        if (expire != NOT_EXPIRE) {
            expire(key, expire);
        }
    }

    /**
     * 查看哈希表 key 中，指定的字段是否存在
     */
    public Boolean hExists(String key, Object field) {
        Boolean res = getHashOperations().hasKey(key, field);
        return res;
    }

    /**
     * 删除一个或多个哈希表字段
     *
     * @param key:键
     * @param fields：字段，一个或者多个字段
     */
    public Long hDel(String key, Object... fields) {
        Long delete = getHashOperations().delete(key, fields);
        return delete;
    }

    /**
     * 获取存储在哈希表中指定字段的值
     *
     * @param key：键
     * @param field：字段
     * @return
     */
    public Object hGet(String key, Object field) {
        return getHashOperations().get(key, field);
    }

    /**
     * 获取在哈希表中指定 key 的所有字段和值
     *
     * @param key
     * @return
     */
    public Map<String, Object> hGetAll(String key) {
        return getHashOperations().entries(key);
    }

    /**
     * 获取所有哈希表中的字段
     *
     * @param key
     */
    public Set hKeys(String key) {
        Set keys = getHashOperations().keys(key);
        return keys;
    }

    /**
     * 从指定key的 hash获取指定字段的值
     *
     * @param key
     * @param map
     */
    public List hMultiGet(String key, Collection map) {
        List list = getHashOperations().multiGet(key, map);
        return list;
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param delta
     */
    public Long hIncrement(String key, String field, long delta) {
        Long increment = getHashOperations().increment(key, field, delta);
        return increment;
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param delta
     */
    public Double hIncrement(String key, String field, double delta) {
        Double increment = getHashOperations().increment(key, field, delta);
        return increment;
    }

    /**
     * 为指定的key添加值，当field不存在时，将值添加
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    public Boolean hPutIfAbsent(String key, String field, Object value) {
        Boolean res = getHashOperations().putIfAbsent(key, field, value);
        return res;
    }

    /**
     * 判断集合大小
     *
     * @param key
     * @return
     */
    public Long hLen(String key) {
        Long size = getHashOperations().size(key);
        return size;
    }

    /**
     * 获取指定key的值
     *
     * @param key
     */
    public List hValues(String key) {
        List list = getHashOperations().values(key);
        return list;
    }

    /**
     * 迭代哈希表中的键值对
     *
     * @param key
     * @param options
     * @return
     */
    public Cursor hScan(String key, ScanOptions options) {
        Cursor scan = getHashOperations().scan(key, options);
        return scan;
    }

    /**
     * 判断字段是否存在
     *
     * @param key
     * @param hashKey
     * @return
     */
    public Boolean hasKey(String key, Object hashKey) {
        Boolean res = getHashOperations().hasKey(key, hashKey);
        return res;
    }

    /**
     * 查询key对应的值长度
     *
     * @param key
     * @param hashKey
     * @return
     */
    public Long lengthOfValue(String key, Object hashKey) {
        Long res = getHashOperations().lengthOfValue(key, hashKey);
        return res;
    }

    /*******************HashMap operation methd end**********************/


    /*******************List operation methd start *********************/

    /**
     * 获取List 集合操作
     *
     * @return
     */
    public ListOperations getListOperations() {
        ListOperations<String, Object> listOperations = redisTemplate.opsForList();
        return listOperations;
    }

    /**
     * 将单个值插入到列表头部
     *
     * @param key
     * @param value
     */
    public Long leftPush(String key, Object value) {
        Long res = leftPush(key, value, DEFAULT_EXPIRE);
        return res;
    }

    /**
     * 将单个值插入到列表头部
     *
     * @param key：key
     * @param value：值
     * @param expire:过期时间，默认秒
     */
    public Long leftPush(String key, Object value, long expire) {
        Long res = redisTemplate.opsForList().leftPush(key, value);
        if (expire != NOT_EXPIRE) {
            expire(key, expire);
        }
        return res;
    }

    /**
     * 将一个或多个值插入到列表头部
     *
     * @param key
     * @param values:多个值
     */
    public Long leftPushAll(String key, Collection values) {
        Long res = getListOperations().leftPushAll(key, values);
        return res;
    }

    /**
     * 移出并获取列表的第一个元素
     *
     * @param key
     */
    public Object leftPop(String key) {
        Object res = getListOperations().leftPop(key);
        return res;
    }

    /**
     * 原子操作，将一个值插入到已存在的列表头部
     *
     * @param key
     * @param value
     * @return
     */
    public Object leftPushIfPresent(String key, String value) {
        return getListOperations().leftPushIfPresent(key, value);
    }

    /**
     * 将单个值插入到列表尾部
     *
     * @param key
     * @param value
     */
    public Long rightPush(String key, Object value) {
        Long res = getListOperations().rightPush(key, value);
        return res;
    }

    /**
     * 将指定key的值添加到 指定值 的之前
     *
     * @param key
     * @param value
     */
    public Long rightPush(String key, Object preValue, Object value) {
        Long res = getListOperations().rightPush(key, preValue, value);
        return res;
    }

    /**
     * 将一个或多个值插入到列表尾部
     *
     * @param key
     * @param values 多个值
     */
    public Long rightPushAll(String key, Collection values) {
        Long res = getListOperations().rightPushAll(key, values);
        return res;
    }

    /**
     * 移除列表的最后一个元素，返回值为移除的元素
     *
     * @param key
     */
    public Object rightPop(String key) {
        return getListOperations().rightPop(key);
    }

    /**
     * 为已存在的列表添加值
     *
     * @param key
     * @param value
     * @return
     */
    public Object rightPushIfPresent(String key, String value) {
        return getListOperations().rightPushIfPresent(key, value);
    }

    /**
     * 移除列表的最后一个元素，并将该元素添加到另一个列表并返回
     *
     * @param sourceKey
     * @param destinationKey
     * @return
     */
    public Object rightPopAndLeftPush(String sourceKey, String destinationKey) {
        return getListOperations().rightPopAndLeftPush(sourceKey, destinationKey);
    }

    /**
     * 查询指定脚标位置的数据
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List lrange(String key, long start, long end) {
        List res = getListOperations().range(key, start, end);
        return res;
    }

    /**
     * 通过索引获取列表中的元素
     *
     * @param key
     * @param index
     * @return
     */
    public Object lindex(String key, long index) {
        Object res = getListOperations().index(key, index);
        return res;
    }

    /**
     * 获取列表长度
     *
     * @param key
     * @return
     */
    public Long len(String key) {
        Long res = getListOperations().size(key);
        return res;
    }

    /**
     * 移除列表元素, 根据参数 COUNT 的值，移除列表中与参数 VALUE 相等的元素
     * count > 0 : 从表头开始向表尾搜索，移除与 VALUE 相等的元素，数量为 COUNT 。
     * count < 0 : 从表尾开始向表头搜索，移除与 VALUE 相等的元素，数量为 COUNT 的绝对值。
     * count = 0 : 移除表中所有与 VALUE 相等的值。
     *
     * @param key
     * @param count
     * @param value
     * @return
     */
    public Long remove(String key, long count, Object value) {
        Long res = getListOperations().remove(key, count, value);
        return res;
    }

    /*******************List operation methd end *********************/


    /*******************Set operation methd start *********************/
    /**
     * 获取无序set集合操作
     *
     * @return
     */
    public SetOperations getSetOperations() {
        SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
        return setOperations;
    }

    /**
     * 向无序集合添加一个或多个成员
     *
     * @param key:       键
     * @param members：成员
     */
    public Long sadd(String key, Object... members) {
        Long res = getSetOperations().add(key, members);
        return res;
    }

    /**
     * 获取集合的成员数,当集合 key 不存在时，返回 0
     *
     * @param key: 键
     * @return
     */
    public Long scard(String key) {
        Long size = getSetOperations().size(key);
        return size;
    }

    /**
     * 比较第一个集合与其他集合之间的差异，也可以认为说第一个集合中独有的元素。不存在的集合 key 将视为空集。
     * <p>
     * 差集的结果来自前面的 FIRST_KEY ,而不是后面的 OTHER_KEY1，也不是整个 FIRST_KEY OTHER_KEY1..OTHER_KEYN 的差集
     *
     * @param key:           键
     * @param otherKey：其他key
     * @return
     */
    public Set sdifference(String key, String otherKey) {
        Set set = getSetOperations().difference(key, otherKey);
        return set;
    }

    /**
     * 比较第一个集合与其他集合之间的差异，也可以认为说第一个集合中独有的元素。不存在的集合 key 将视为空集。
     * <p>
     * 差集的结果来自前面的 FIRST_KEY ,而不是后面的 OTHER_KEY1，也不是整个 FIRST_KEY OTHER_KEY1..OTHER_KEYN 的差集
     *
     * @param key:            键
     * @param otherKeys：其他key
     * @return
     */
    public Set sdifference(String key, Collection otherKeys) {
        Set set = getSetOperations().difference(key, otherKeys);
        return set;
    }

    /**
     * 将给定集合之间的差集存储在指定的集合中。如果指定的集合 key 已存在，则会被覆盖
     *
     * @param key:           键
     * @param otherKey：其他key
     * @return
     */
    public Long sdifferenceAndStore(String key, String otherKey, String destKey) {
        Long res = getSetOperations().differenceAndStore(key, otherKey, destKey);
        return res;
    }

    /**
     * 将给定集合之间的差集存储在指定的集合中。如果指定的集合 key 已存在，则会被覆盖
     *
     * @param key:            键
     * @param otherKeys：其他key
     * @return
     */
    public Long sdifferenceAndStore(String key, Collection otherKeys, String destKey) {
        Long res = getSetOperations().differenceAndStore(key, otherKeys, destKey);
        return res;
    }

    /**
     * 返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集时，结果也为空集(根据集合运算定律)
     *
     * @param key:           键
     * @param otherKey：其他key
     * @return
     */
    public Set sintersect(String key, String otherKey) {
        Set set = getSetOperations().intersect(key, otherKey);
        return set;
    }

    /**
     * 返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集时，结果也为空集(根据集合运算定律)
     *
     * @param key:            键
     * @param otherKeys：其他key
     * @return
     */
    public Set sintersect(String key, Collection otherKeys) {
        Set set = getSetOperations().intersect(key, otherKeys);
        return set;
    }


    /**
     * 将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在，则将其覆盖
     *
     * @param key:           键
     * @param otherKey：其他key
     * @param destKey:       目标集合
     * @return
     */
    public Long sintersectAndStore(String key, String otherKey, String destKey) {
        Long res = getSetOperations().intersectAndStore(key, otherKey, destKey);
        return res;
    }

    /**
     * 将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在，则将其覆盖
     *
     * @param key:            键
     * @param otherKeys：其他key
     * @param destKey:        目标集合
     * @return
     */
    public Long sintersectAndStore(String key, Collection otherKeys, String destKey) {
        Long res = getSetOperations().intersectAndStore(key, otherKeys, destKey);
        return res;
    }

    /**
     * 判断 member 元素是否是集合 key 的成员
     *
     * @param key:        键
     * @param member：集合成员
     */
    public Boolean isMember(String key, Object member) {
        Boolean res = getSetOperations().isMember(key, member);
        return res;
    }

    /**
     * 返回集合中的所有成员
     *
     * @param key 键
     * @return
     */
    public Set smembers(String key) {
        Set members = getSetOperations().members(key);
        return members;
    }

    /**
     * 将 member 元素从 source 集合移动到 destination 集合
     *
     * @param key：键
     * @param member:      成员
     * @param destKey：目标集合
     * @return
     */
    public Boolean smove(String key, Object member, String destKey) {
        Boolean res = getSetOperations().move(key, member, destKey);
        return res;
    }

    /**
     * 移除并返回集合中的一个随机元素
     *
     * @param key
     * @return
     */
    public Object smove(String key) {
        Object res = getSetOperations().pop(key);
        return res;
    }

    /**
     * 返回集合中一个或多个随机数
     * 如果 count 为正数，且小于集合基数，那么命令返回一个包含 count 个元素的数组，数组中的元素各不相同。如果 count 大于等于集合基数，那么返回整个集合。
     * 如果 count 为负数，那么命令返回一个数组，数组中的元素可能会重复出现多次，而数组的长度为 count 的绝对值。
     * 该操作和 SPOP 相似，但 SPOP 将随机元素从集合中移除并返回，而 Srandmember 则仅仅返回随机元素，而不对集合进行任何改动
     *
     * @param key
     * @param count
     * @return
     */
    public Object smove(String key, long count) {
        Object res = getSetOperations().pop(key, count);
        return res;
    }

    /**
     * 移除集合中的一个或多个成员元素，不存在的成员元素会被忽略。当 key 不是集合类型，返回一个错误
     *
     * @param key：键
     * @param values: 集合成员
     * @return
     */
    public Object sremove(String key, Object... values) {
        Object res = getSetOperations().remove(key, values);
        return res;
    }

    /**
     * 移除并返回集合中的一个随机元素
     *
     * @param key
     * @return
     */
    public Object spop(String key) {
        Object pop = getSetOperations().pop(key);
        return pop;
    }

    /**
     * 移除并返回集合中的一个随机元素
     *
     * @param key
     * @return
     */
    public List spop(String key, long count) {
        List list = getSetOperations().pop(key, count);
        return list;
    }

    /**
     * 返回集合中一个或多个随机数
     *
     * @param key
     * @return
     */
    public Object srandomMember(String key) {
        Object res = getSetOperations().randomMember(key);
        return res;
    }

    /**
     * 返回集合中一个或多个随机数
     *
     * @param key
     * @return
     */
    public List srandomMembers(String key, long count) {
        List list = getSetOperations().randomMembers(key, count);
        return list;
    }

    /**
     * 返回所有给定集合的并集
     *
     * @param key      键
     * @param otherKey 其他key
     * @return
     */
    public Set sunion(String key, String otherKey) {
        Set members = getSetOperations().union(key, otherKey);
        return members;
    }

    /**
     * 返回所有给定集合的并集
     *
     * @param key：键
     * @param otherKeys 其他key
     * @return
     */
    public Set sunion(String key, Collection otherKeys) {
        Set members = getSetOperations().union(key, otherKeys);
        return members;
    }

    /**
     * 所有给定集合的并集存储在 destination 集合中
     *
     * @param key      键
     * @param otherKey 其他key
     * @param destKey  目标key
     * @return
     */
    public Long sunionAndStore(String key, String otherKey, String destKey) {
        Long res = getSetOperations().unionAndStore(key, otherKey, destKey);
        return res;
    }

    /**
     * 所有给定集合的并集存储在 destination 集合中
     *
     * @param key       键
     * @param otherKeys 其他key
     * @param destKey   目标key
     * @return
     */
    public Long sunionAndStore(String key, Collection otherKeys, String destKey) {
        Long res = getSetOperations().unionAndStore(key, otherKeys, destKey);
        return res;
    }

    /**
     * 查询集合大小
     *
     * @param key
     * @return
     */
    public Long ssize(String key) {
        Long res = getSetOperations().size(key);
        return res;
    }
    /*******************Set operation methd end *********************/


    /*******************ZSet operation methd start *********************/
    /**
     * 获取有序set集合操作
     *
     * @return
     */
    public ZSetOperations getZSetOperations() {
        ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations;
    }

    /**
     * 向有序集合添加一个或多个成员，或者更新已存在成员的分数
     *
     * @param key
     * @param member:        集合成员
     * @param score--分值，用于排序
     */
    public void zadd(String key, Object member, double score) {
        getZSetOperations().add(key, member, score);
    }

    /**
     * 向有序集合添加一个或多个成员，或者更新已存在成员的分数
     *
     * @param key
     * @param map: value-score, 值-分值，用于排序
     */
    public Long zadd(String key, Map<Object, Double> map) {
        if (map == null || map.size() <= 0) return 0L;
        Set<TypedTuple> tuples = new HashSet<>();
        for (Object value : map.keySet()) {
            Double score = map.get(value);
            TypedTuple tuple = new DefaultTypedTuple(value, score);
            tuples.add(tuple);
        }
        Long res = getZSetOperations().add(key, tuples);
        return res;
    }

    /**
     * 向有序集合添加一个或多个成员，或者更新已存在成员的分数
     *
     * @param key
     * @param tuples: value-score, 值-分值，用于排序
     */
    public Long zadd(String key, Set<TypedTuple<Object>> tuples) {
        Long res = getZSetOperations().add(key, tuples);
        return res;
    }

    /**
     * 获取有序集合的成员数
     *
     * @param key
     * @return
     */
    public Long zcard(String key) {
        Long res = getZSetOperations().zCard(key);
        return res;
    }

    /**
     * 计算在有序集合中指定区间分数值在 min 和 max 之间的成员的数量
     *
     * @param key
     * @param minScore:最小分数
     * @param maxScore：最大分数
     * @return
     */
    public Long zcount(String key, double minScore, double maxScore) {
        Long res = getZSetOperations().count(key, minScore, maxScore);
        return res;
    }

    /**
     * 在{@code key}和{@code otherKey}处相交排序集，并将结果存储在目标{@code destKey}
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public Long zintersectAndStore(String key, Object otherKey, Object destKey) {
        Long res = getZSetOperations().intersectAndStore(key, otherKey, destKey);
        return res;
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public Long zsizeOfKey(String key) {
        return getZSetOperations().size(key);
    }

    /**
     * 通过索引区间返回有序集合指定区间内的成员
     *
     * @param key：键
     * @param start：开始位置
     * @param end：结束位置
     */
    public Set zrange(String key, long start, long end) {
        Set res = getZSetOperations().range(key, start, end);
        return res;
    }

    /**
     * 通过字典区间返回有序集合的成员
     *
     * @param key：键
     * @param range:分数范围
     */
    public Set zrangeByLex(String key, RedisZSetCommands.Range range) {
        Set res = getZSetOperations().rangeByLex(key, range);
        return res;
    }

    /**
     * 通过字典区间返回有序集合的成员
     *
     * @param key：键
     * @param range:分数范围
     * @param limit：查询数量
     */
    public Set zrangeByLex(String key, RedisZSetCommands.Range range, RedisZSetCommands.Limit limit) {
        Set res = getZSetOperations().rangeByLex(key, range, limit);
        return res;
    }

    /**
     * 根据Key查询，分值在min和max范围内的数据
     *
     * @param key：键
     * @param min：最小分数
     * @param max：最大分数
     * @return Set<Object>
     */
    public Set<Object> zrangeByScore(String key, double min, double max) {
        return getZSetOperations().rangeByScore(key, min, max);
    }

    /**
     * 通过字典区间查询有序集合的成员
     *
     * @param key：键
     * @param min：最小分数
     * @param max：最大分数
     * @param offset：偏移量
     * @param count：数量
     * @return Set<Object>
     */
    public Set<Object> zrangeByScore(String key, double min, double max, long offset, long count) {
        return getZSetOperations().rangeByScore(key, min, max, offset, count);
    }

    /**
     * 查询有序集中指定成员的排名。其中有序集成员按分数值递增(从小到大)顺序排列
     *
     * @param key：键
     * @param member: 集合成员
     */
    public Long zrank(String key, Object member) {
        Long rank = getZSetOperations().rank(key, member);
        return rank;
    }

    /**
     * 查询有序集合中指定成员的排名，有序集成员按分数值递减(从大到小)排序
     *
     * @param key：键
     * @param member: 集合成员
     * @return
     */
    public Long zreverseRank(String key, Object member) {
        Long res = getZSetOperations().reverseRank(key, member);
        return res;
    }

    /**
     * 删除指定key的成员
     *
     * @param key：键
     * @param members：需要删除的成员
     * @return
     */
    public Long zremove(String key, Object... members) {
        Long res = getZSetOperations().remove(key, members);
        return res;
    }

    /**
     * 删除有序集中，指定排名(rank)区间内的所有成员
     *
     * @param key：键
     * @param start：开始位置
     * @param end：结束位置
     * @return
     */
    public Long zremoveRange(String key, long start, long end) {
        Long res = getZSetOperations().removeRange(key, start, end);
        return res;
    }

    /**
     * 删除有序集合中给定的分数区间的所有成员
     *
     * @param key
     * @param min：最小分数
     * @param max：最大分数
     */
    public Long zremoveRangeByScore(String key, double min, double max) {
        Long res = getZSetOperations().removeRangeByScore(key, min, max);
        return res;
    }

    /**
     * 查询有序集中指定区间内的成员，通过索引，分数从高到低，
     * <p>
     * 其中成员的位置按分数值递减(从大到小)来排列。
     * <p>
     * 具有相同分数值的成员按字典序的逆序(reverse lexicographical order)排列。
     * <p>
     *
     * @param key：键
     * @param start：开始位置
     * @param end：结束位置
     */
    public Set zreverseRange(String key, long start, long end) {
        Set set = getZSetOperations().reverseRange(key, start, end);
        return set;
    }


    /**
     * 查询有序集中指定分数区间内的所有的成员。有序集成员按分数值递减(从大到小)的次序排列
     * 具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列
     *
     * @param key
     * @param min：最小分数
     * @param max：最大分数
     * @return
     */
    public Set zreverseRangeByScore(String key, double min, double max) {
        Set set = getZSetOperations().reverseRangeByScore(key, min, max);
        return set;
    }

    /**
     * 查询有序集中指定分数区间内的所有的成员。有序集成员按分数值递减(从大到小)的次序排列
     * 具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列
     *
     * @param key
     * @param min：最小分数
     * @param max：最大分数
     * @param offset：偏移量
     * @param count：数量
     * @return
     */
    public Set zreverseRangeByScore(String key, double min, double max, long offset, long count) {
        Set set = getZSetOperations().reverseRangeByScore(key, min, max, offset, count);
        return set;
    }

    /**
     * 获取从{@code start}到{@code end}范围内的{Tuple}集，
     *
     * @param key：键
     * @param start：开始位置
     * @param end：结束位置
     * @return
     */
    public Set zreverseRangeWithScores(String key, long start, long end) {
        Set set = getZSetOperations().reverseRangeWithScores(key, start, end);
        return set;
    }

    /**
     * 获取从{@code start}到{@code end}范围内的{Tuple}集，
     * 其中分数介于{@code min}和{@code min}之间
     *
     * @param key
     * @param min：最小分数
     * @param max：最大分数
     * @return
     */
    public Set zreverseRangeByScoreWithScores(String key, double min, double max) {
        Set set = getZSetOperations().reverseRangeByScoreWithScores(key, min, max);
        return set;
    }

    /**
     * 获取从{@code start}到{@code end}范围内的{Tuple}集，
     * 其中分数介于{@code min}和{@code min}之间
     * <p>
     * *{@code max}从排序集排序高->低
     *
     * @param key
     * @param min：最小分数
     * @param max：最大分数
     * @param offset：偏移量
     * @param count：数量
     * @return
     */
    public Set zreverseRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        Set set = getZSetOperations().reverseRangeByScoreWithScores(key, min, max, offset, count);
        return set;
    }

    /**
     * 计算给定的一个或多个有序集的并集，并存储在新的 key 中
     *
     * @param key
     * @param otherKey
     * @param destKey
     */
    public Long zunionAndStore(String key, String otherKey, String destKey) {
        Long res = getZSetOperations().unionAndStore(key, otherKey, destKey);
        return res;
    }

    /**
     * 查询有序集中，成员的分数值。 如果成员元素不是有序集 key 的成员，或 key 不存在，返回 nil
     *
     * @param key
     * @param member: 成员
     */
    public Double zscore(String key, Object member) {
        Double score = getZSetOperations().score(key, member);
        return score;
    }
    /*******************ZSet operation methd end *********************/
}
